home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Pascal / Snippets / ModalTextEdit 1.0 / ModalTextEdit.p < prev    next >
Encoding:
Text File  |  1995-05-20  |  11.5 KB  |  456 lines  |  [TEXT/PJMM]

  1.  
  2. {    Modal Dialog TextEdit useritem snippet}
  3. {    Steve Falkenburg-- MacDTS}
  4.  
  5. {    This snippet shows the steps necessary to implement a scrolling, editable text field}
  6. {    in a dialog.  You may want to do this if you will be requiring the user to enter more than}
  7. {    255 characters (the limit for editText items), if you want a different font for several}
  8. {    different editText items, or it you want to add scrolling support to an editible text item.}
  9.  
  10. program ModalTextEdit;
  11.  
  12. { constants}
  13.  
  14.     const
  15.         kMyDialog = 128;
  16. {kInFront = WindowPtr(-1);}
  17.         kEditTextItem = 2;
  18.         kScrollerItem = 3;
  19.         kMargin = 4;
  20.         kPageLines = 16;
  21.         kScrollToTop = 0;
  22.         kScrollToBottom = 1;
  23.         kMaxLines = 128;
  24.         kCheckOneItem = 5;
  25.         kCheckTwoItem = 6;
  26.  
  27.  
  28. (* initialize the Mac managers *)
  29.  
  30.     procedure InitStuff;
  31.     begin
  32. {$IFC UNDEFINED THINK_PASCAL}
  33.         InitGraf(@qd.thePort);
  34.         InitFonts;
  35.         InitWindows;
  36.         InitMenus;
  37.         TEInit;
  38.         InitDialogs(nil);
  39. {$ENDC}
  40.         InitCursor;
  41.         FlushEvents(everyEvent, 0);
  42.     end;
  43.  
  44. (*    utility procedure to return a handle to the scrollbar control*)
  45.  
  46.     function GetScrollBar (theDialog: DialogPtr): ControlHandle;
  47.         var
  48.             theScroller: ControlHandle;
  49.             iType: Integer;
  50.             iRect: Rect;
  51.     begin
  52.         GetDItem(theDialog, kScrollerItem, iType, Handle(theScroller), iRect);
  53.         GetScrollBar := theScroller;
  54.     end; {GetScrollBar}
  55.  
  56.  
  57. (*    utility procedure to return the textedit record for the given dialog *)
  58.  
  59.     function GetTEHandle (theDialog: DialogPtr): TEHandle;
  60.     begin
  61.         GetTEHandle := TEHandle(GetWRefCon(WindowPtr(theDialog)));
  62.     end;
  63.  
  64.  
  65. (*    dialog user item draw procedure for text box.  It just calls FrameRect *)
  66.  
  67.     procedure EditTextDrawProc (theDialog: DialogPtr; theItem: Integer);
  68.         var
  69.             iType: Integer;
  70.             iHndl: Handle;
  71.             iRect: Rect;
  72.             savePort: GrafPtr;
  73.     begin
  74.         GetPort(savePort);
  75.         SetPort(theDialog);
  76.  
  77.         GetDItem(theDialog, theItem, iType, iHndl, iRect);
  78.         FrameRect(iRect);
  79.  
  80.         SetPort(savePort);
  81.     end; {EditTextDrawProc}
  82.  
  83.  
  84.  
  85. (*    sets the text top line to be the same as the current scrollbar position.  this is called after}
  86. {    a thumb movement in the scrollbar.}
  87. {*)
  88.  
  89.     procedure ReAlignTextToScrollbar (theDialog: DialogPtr);
  90.         var
  91.             theTE: TEHandle;
  92.             scrollBar: ControlHandle;
  93.             controlScrollPosition, textScrollPosition, scrollDelta, scrollPix: Integer;
  94.     begin
  95.         theTE := GetTEHandle(theDialog);
  96.         scrollBar := GetScrollBar(theDialog);
  97.  
  98.         controlScrollPosition := GetCtlValue(scrollBar);
  99.         textScrollPosition := (theTE^^.viewRect.top - theTE^^.destRect.top) div theTE^^.lineHeight;
  100.         scrollDelta := textScrollPosition - controlScrollPosition;
  101.         scrollPix := scrollDelta * theTE^^.lineHeight;
  102.         TEScroll(0, scrollPix, theTE);
  103.     end; {ReAlignTextToScrollbar}
  104.  
  105.  
  106. (*    sets the scrollbar thumb to the current text position.  this is called after autoscrolling,}
  107. {    which may occur after a call to TEKey, or during a drag-scroll}
  108. {*)
  109.  
  110.     procedure ReAlignScrollbarToText (theDialog: DialogPtr);
  111.         var
  112.             theTE: TEHandle;
  113.             scrollBar: ControlHandle;
  114.             textScrollPosition: Integer;
  115.     begin
  116.         theTE := GetTEHandle(theDialog);
  117.         scrollBar := GetScrollBar(theDialog);
  118.  
  119.         textScrollPosition := (theTE^^.viewRect.top - theTE^^.destRect.top) div theTE^^.lineHeight;
  120.         SetCtlValue(scrollBar, textScrollPosition);
  121.     end; {ReAlignScrollbarToText}
  122.  
  123.  
  124. (*    scrolls the text by the delta passed in to the function.  called in response to clicking the*)
  125. (*    arrows or page areas of the scrollbar to move the text*)
  126.  
  127.     procedure ScrollText (theDialog: DialogPtr; lines: Integer);
  128.         var
  129.             theTE: TEHandle;
  130.             scrollPix: Integer;
  131.             textScrollPosition: Integer;
  132.     begin
  133.         theTE := GetTEHandle(theDialog);
  134.  
  135.         textScrollPosition := (theTE^^.viewRect.top - theTE^^.destRect.top) div theTE^^.lineHeight;
  136.         if ((textScrollPosition + lines) < 0) then
  137.             lines := -textScrollPosition;
  138.         if ((textScrollPosition + lines) > kMaxLines) then
  139.             lines := kMaxLines - textScrollPosition;
  140.  
  141.         scrollPix := lines * theTE^^.lineHeight;
  142.  
  143.         TEScroll(0, -scrollPix, theTE);
  144.     end; {ScrollText}
  145.  
  146.  
  147. {    text drag callback procedure.  this routine handles drag scrolling by checking to see if we}
  148. {    are in the area where drag-scrolling is necessary, and calling scrolltext followed by a}
  149. {    scrollbar realignment}
  150.  
  151.     function MyTEClickProc: Boolean;
  152.         var
  153.             pt: Point;
  154.             theDialog: DialogPtr;
  155.             theControl: ControlHandle;
  156.             theTE: TEHandle;
  157.             textRect: Rect;
  158.             scrollLines: Integer;
  159.             savePort: GrafPtr;
  160.             saveClip: RgnHandle;
  161.     begin
  162.         GetMouse(pt);
  163.         theDialog := DialogPtr(FrontWindow);
  164.         theTE := GetTEHandle(theDialog);
  165.  
  166.         GetPort(savePort);
  167.         SetPort(theDialog);
  168.  
  169.         saveClip := NewRgn;
  170.         GetClip(saveClip);
  171.         ClipRect(theDialog^.portRect);
  172.  
  173.         scrollLines := 0;
  174.         textRect := theTE^^.viewRect;
  175.         if (pt.v < textRect.top) then
  176.             scrollLines := -1
  177.         else if pt.v > textRect.bottom then
  178.             scrollLines := 1;
  179.  
  180.         if scrollLines <> 0 then
  181.             begin
  182.                 ScrollText(theDialog, scrollLines);
  183.                 ReAlignScrollbarToText(theDialog);
  184.             end;
  185.  
  186.         SetClip(saveClip);
  187.         DisposeRgn(saveClip);
  188.         SetPort(savePort);
  189.         MyTEClickProc := true;
  190.     end; {MyTEClickProc}
  191.  
  192.  
  193.  
  194. (*    handler for null events.  used in our case to blink the insertion point}
  195. {*)
  196.  
  197.     procedure HandleIdle (theDialog: DialogPtr);
  198.         var
  199.             theTE: TEHandle;
  200.     begin
  201.         theTE := GetTEHandle(theDialog);
  202.         TEIdle(theTE);
  203.     end; {HandleIdle}
  204.  
  205.  
  206. (*    activate event handler.  we take this opportunity to call TEActivate to activate the textedit box*)
  207.  
  208.     procedure HandleActivate (theDialog: DialogPtr);
  209.         var
  210.             theTE: TEHandle;
  211.     begin
  212.         theTE := GetTEHandle(theDialog);
  213.         TEActivate(theTE);
  214.     end;
  215.  
  216. (*    trackcontrol callback used to determine which direction to scroll the text, and by how much.}
  217. {    once this is known, the text is scrolled, and the scrollbar adjusted.}
  218.  
  219.     procedure ScrollBarAction (theControl: ControlHandle; part: Integer);
  220.         var
  221.             theDialog: DialogPtr;
  222.             lines: Integer;
  223.             ctlValue, ctlMax, ctlMin: Integer;
  224.     begin
  225.         ctlMax := GetCtlMax(theControl);
  226.         ctlMin := GetCtlMin(theControl);
  227.         ctlValue := GetCtlValue(theControl);
  228.  
  229.         theDialog := theControl^^.contrlOwner;
  230.  
  231.         case part of
  232.             inUpButton: 
  233.                 lines := -1;
  234.             inDownButton: 
  235.                 lines := 1;
  236.             inPageUp: 
  237.                 lines := -kPageLines;
  238.             inPageDown: 
  239.                 lines := kPageLines;
  240.             otherwise
  241.                 exit(ScrollBarAction);
  242.         end; {case}
  243.  
  244.         if ctlValue + lines > ctlMax then
  245.             lines := ctlMax - ctlValue;
  246.         if ctlValue + lines < ctlMin then
  247.             lines := ctlMin - ctlValue;
  248.  
  249.         if lines <> 0 then
  250.             begin
  251.                 ScrollText(theDialog, lines);
  252.                 SetCtlValue(theControl, ctlValue + lines);
  253.             end;
  254.     end; {ScrollBarAction}
  255.  
  256. {    here, we see which part of the scrollbar was clicked in by calling findcontrol.  trackcontrol}
  257. {    is then called with the appropriate action proc if in one of the buttons or page areas.  if}
  258. {    in the thumb, the text is simply re-aligned to the new scrollbar position}
  259.  
  260.     procedure HandleScroller (theDialog: DialogPtr; pt: Point);
  261.         var
  262.             part: Integer;
  263.             theControl: ControlHandle;
  264.     begin
  265.         part := FindControl(pt, theDialog, theControl);
  266.         case part of
  267.             inUpButton, inDownButton, inPageUp, inPageDown: 
  268.                 if TrackControl(theControl, pt, @ScrollBarAction) = 0 then
  269.                     ;
  270.             inThumb: 
  271.                 begin
  272.                     if TrackControl(theControl, pt, nil) = 0 then
  273.                         ;
  274.                     ReAlignTextToScrollbar(theDialog);
  275.                 end;
  276.         end; {case}
  277.     end; {HandleScroller}
  278.  
  279.  
  280. {    mouse-down hander.  here, we see if the mousedown was in the scrollbar or in the textedit}
  281. {    record.  if in the textedit item, we call teclick.  If in the scrollbar, we call handlescroller}
  282. {    to do further processing}
  283.  
  284.     function HandleMouse (theDialog: DialogPtr; pt: Point; modifiers: Integer): Boolean;
  285.         var
  286.             iType: Integer;
  287.             iHndl: Handle;
  288.             textRect, scrollerRect: Rect;
  289.             theTE: TEHandle;
  290.             savePort: GrafPtr;
  291.             shiftDown, result: Boolean;
  292.             theControl: ControlHandle;
  293.             part: Integer;
  294.     begin
  295.         GetPort(savePort);
  296.         SetPort(theDialog);
  297.  
  298.         shiftDown := BAnd(modifiers, shiftKey) <> 0;
  299.         GlobalToLocal(pt);
  300.  
  301.         GetDItem(theDialog, kEditTextItem, iType, iHndl, textRect);
  302.         GetDItem(theDialog, kScrollerItem, iType, iHndl, scrollerRect);
  303.  
  304.         if PtInRect(pt, textRect) then
  305.             begin
  306.                 theTE := GetTEHandle(theDialog);
  307.                 TEClick(pt, shiftDown, theTE);
  308.                 result := true;
  309.             end
  310.         else if PtInRect(pt, scrollerRect) then
  311.             begin
  312.                 HandleScroller(theDialog, pt);
  313.                 result := true;
  314.             end
  315.         else
  316.             result := false;
  317.  
  318.         SetPort(savePort);
  319.  
  320.         HandleMouse := result;
  321.     end; {HandleMouse}
  322.  
  323.  
  324. {    Creates the necessary data structures necessary to use the textedit item in our dialog.  A}
  325. {    handle to the TextEdit record is stored in the Dialog's window refCon field.}
  326.  
  327.     procedure SetupDialog (theDialog: DialogPtr);
  328.         var
  329.             iType: Integer;
  330.             iHndl: Handle;
  331.             iRect: Rect;
  332.             theControl: ControlHandle;
  333.             fontNum: Integer;
  334.             theTE: TEHandle;
  335.     begin
  336.         SetPort(theDialog);
  337.  
  338.         GetDItem(theDialog, kScrollerItem, iType, Handle(theControl), iRect);    { set up the scroll bar}
  339.         SetCtlMin(theControl, 0);                                        { (it's stored in a CNTL)}
  340.         SetCtlMax(theControl, kMaxLines);
  341.  
  342.         GetDItem(theDialog, kEditTextItem, iType, iHndl, iRect);
  343.         SetDItem(theDialog, kEditTextItem, iType, @EditTextDrawProc, iRect);
  344.  
  345.         InsetRect(iRect, kMargin, kMargin);
  346.  
  347.         GetFNum('geneva', fontNum);
  348.         TextFont(fontNum);
  349.         theTE := TENew(iRect, iRect);            { create our textedit item}
  350.         GetFNum('chicago', fontNum);
  351.         TextFont(fontNum);
  352.  
  353.         SetClikLoop(@MyTEClickProc, theTE);        { callback for drag-scrolling}
  354.         TEAutoView(true, theTE);                    { turn auto-scroll on for text entry}
  355.  
  356.         SetWRefCon(theDialog, LongInt(theTE));
  357.     end; {SetupDialog}
  358.  
  359.  
  360.  
  361. (* free the memory taken by the textedit record before closing the dialog *)
  362.  
  363.     procedure PrepareFreeDialog (theDialog: DialogPtr);
  364.         var
  365.             theTE: TEHandle;
  366.     begin
  367.         theTE := GetTEHandle(theDialog);
  368.         TEDispose(theTE);
  369.     end; {PrepareFreeDialog}
  370.  
  371.  
  372. (*    this is the main dispatcher for events to be passed off to the scroll bar or textedit box.*)
  373. (*    looks sort of like a WaitNextEvent event handler. *)
  374.  
  375.     function MyDialogFilter (theDialog: DialogPtr; var ev: EventRecord; var itemHit: Integer): Boolean;
  376.         var
  377.             theChar: char;
  378.  
  379. (*    dialog filter event handler for keypresses.  All keypresses are passed to the textedit box*)
  380.         procedure HandleKeyPress (theDialog: DialogPtr; theChar: char);
  381.             var
  382.                 theTE: TEHandle;
  383.         begin
  384.             theTE := GetTEHandle(theDialog);
  385.             TEKey(theChar, theTE);
  386.             ReAlignScrollbarToText(theDialog);
  387.         end;
  388.  
  389.     begin {MyDialogFilter}
  390.         case ev.what of
  391.             keyDown, autoKey: 
  392.                 begin
  393.                     theChar := Char(BAnd(ev.message, charCodeMask));
  394.                     HandleKeyPress(theDialog, theChar);
  395.                     MyDialogFilter := true;
  396.                 end;
  397.             nullEvent: 
  398.                 begin
  399.                     HandleIdle(theDialog);
  400.                     MyDialogFilter := false;
  401.                 end;
  402.             activateEvt: 
  403.                 begin
  404.                     HandleActivate(theDialog);
  405.                     MyDialogFilter := false;
  406.                 end;
  407.             mouseDown: 
  408.                 MyDialogFilter := HandleMouse(theDialog, ev.where, ev.modifiers);
  409.             otherwise
  410.                 MyDialogFilter := false;
  411.         end;
  412.     end; {MyDialogFilter}
  413.  
  414.  
  415. (*    display dialog, and handle pretty standard ModalDialog loop.  The modal dialog loop doesn't}
  416. {    handle item hits to the scroll bar or text items.  These are handled through the filter}
  417. {    procedure}
  418. {*)
  419.  
  420.     procedure DoDialog;
  421.         var
  422.             theDialog: DialogPtr;
  423.             item: Integer;
  424.             checkBoxControl: ControlHandle;
  425.             iType: Integer;
  426.             iRect: Rect;
  427.     begin
  428.         theDialog := GetNewDialog(kMyDialog, nil, WindowPtr(-1));
  429.         SetupDialog(theDialog);
  430.  
  431.         repeat
  432.             begin
  433.                 ModalDialog(@MyDialogFilter, item);
  434.                 case item of
  435.                     kCheckOneItem,    { check boxes}
  436.                     kCheckTwoItem: 
  437.                         begin
  438.                             GetDItem(theDialog, item, iType, Handle(checkBoxControl), iRect);
  439.                             SetCtlValue(checkBoxControl, Integer(not Boolean(GetCtlValue(checkBoxControl))));
  440.                         end;
  441.                 end; {case}
  442.             end;
  443.         until item = ok;
  444.  
  445.         PrepareFreeDialog(theDialog);
  446.         DisposeDialog(theDialog);
  447.     end; {DoDialog}
  448.  
  449.  
  450.  (* main entry point *)
  451.  
  452. begin
  453.     InitStuff;
  454.     DoDialog;
  455.     ExitToShell;
  456. end.